#include "StdAfx.h"
#include "ConfigException.h"
#include "Config.h"


Config::Config(std::string filePath) : m_state(State_None)
{
	m_infile.open(filePath, std::ios_base::in);
	if(!m_infile.is_open())
		throw std::exception("Can not open infile!");

	std::string curLine, category, name, value;
	char chr;
	while(std::getline(m_infile, curLine))
	{
		for(auto i = curLine.begin(); i != curLine.end(); ++i)
		{
			chr = (*i);
			if(chr == '#')
				break;
			else if(chr == '<')
			{
				m_state = State_Category;
				category.clear();
			}
			else if(chr == '>')
			{
				m_state = State_Keyword;
			}
			else if(chr == '=')
			{
				m_state = State_Value;
			}
			else if(chr == ' ' || chr == '\t')
			{
				if(m_state != State_Value)
					continue;
				if(i > curLine.begin() && (*(i-1)) == '=')
					continue;
			}
			else if((i+1) == curLine.end())
			{
				if(m_state == State_Value)
					value.push_back(chr);
				else
					name.push_back(chr);

				std::transform(category.begin(), category.end(), category.begin(), tolower);
				std::transform(name.begin(), name.end(), name.begin(), tolower);
				m_tokens[category][name] = value;
				m_state = State_Keyword;
			}
			else
			{
				switch(m_state)
				{
				case State_Category: category.push_back(chr); break;
				case State_Keyword: name.push_back(chr); break;
				case State_Value: value.push_back(chr); break;
				case State_None: throw ConfigException(0x400+2, __FUNCTION__);
				}
			}
		}

		if(m_state != State_None && m_state != State_Keyword && m_state != State_Value)
			throw ConfigException(0x400+2, __FUNCTION__);
		
		name.clear();
		value.clear();
		curLine.clear();
	}
}


const std::string& Config::GetTokenValue(const std::string& category, const std::string& tokenName) const
{
	std::string cat(category), token(tokenName);
	std::transform(category.begin(), category.end(), cat.begin(), tolower);
	std::transform(tokenName.begin(), tokenName.end(), token.begin(), tolower);
	return m_tokens.at(cat).at(token);
}

const uint32 Config::getUInt32(const std::string& category, const std::string& tokenName) const {
	const std::string& str = GetTokenValue(category, tokenName);
	std::stringstream strm;
	strm << str;
	uint32 ret;
	if(strm >> ret)
		return ret;

	throw ConfigException(ERROR_CLUSTER_INVALID_STRING_FORMAT, __FUNCTION__);
}

const int32 Config::getInt32(const std::string& category, const std::string& tokenName) const {
	const std::string& str = GetTokenValue(category, tokenName);
	std::stringstream strm;
	strm << str;
	int32 ret;
	if(strm >> ret)
		return ret;

	throw ConfigException(ERROR_CLUSTER_INVALID_STRING_FORMAT, __FUNCTION__);
}

const float Config::getFloat(const std::string& category, const std::string& tokenName) const {
	const std::string& str = GetTokenValue(category, tokenName);
	std::stringstream strm;
	strm << str;
	float ret;
	if(strm >> ret)
		return ret;

	throw ConfigException(ERROR_CLUSTER_INVALID_STRING_FORMAT, __FUNCTION__);
}

const bool Config::getBoolean(const std::string& category, const std::string& tokenName) const {
	const std::string& str = GetTokenValue(category, tokenName);
	std::stringstream strm;
	strm << str;
	bool ret;
	if(strm >> ret)
		return ret;

	throw ConfigException(ERROR_CLUSTER_INVALID_STRING_FORMAT, __FUNCTION__);
}